package Services;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;



import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Query;

import Entities.DirtyBit;
import Entities.RTentry;
import Entities.User;

public class UserServiceDBimpl implements UserService{

	List<RTentry> highscores;
	DirtyBit dirtybit;

	Comparator<RTentry> comparator = new RTcomparator();
	Objectify ofy;

	private static UserServiceDBimpl instance = null;

	public void init(){

		ObjectifyService.register(User.class);
		ObjectifyService.register(RTentry.class);
		ObjectifyService.register(DirtyBit.class);



		highscores = new ArrayList<RTentry>();
		dirtybit = new DirtyBit();

		ofy = ObjectifyService.begin();

		//erase dirty-bit from DB
		DirtyBit oldDirtyBit = ofy.query(DirtyBit.class).get();
		ofy.delete(oldDirtyBit);
	}

	public List<RTentry> getRT() {
		int dbWasChanged = 1;

		//query for dirty bit 
		Query<DirtyBit> qdirtybit = ofy.query(DirtyBit.class);
		for (DirtyBit dirtbit: qdirtybit) {
			dbWasChanged = dirtbit.isDirty();
		}

		//is the bit dirty?
		if(true){
			highscores = new ArrayList<RTentry>();
			Query<RTentry> q = ofy.query(RTentry.class);
			for (RTentry rte: q) {
				highscores.add(rte);
			}

			//update that the dirtybit is now false, as we have the highscore in memory
			dirtybit.setDirty(0);
			ofy.put(dirtybit);
		}

		// query for all users who have the name 'name'

		if(highscores == null){
			return null;
		}

		Collections.sort(highscores,comparator);
		return highscores;
	}

	public User getUserByEmail(String email) {
		User u = ofy.query(User.class).filter("email", email).get();


		if(u == null){
			return null;
		}
		else return u;//TODO: iterate
	}



	public User getUserByName(String name) {
		User u = ofy.query(User.class).filter("name", name).get();
		if(u == null){
			return null;
		}
		else return u;//TODO: iterate
	}

	@Override
	public User getUserByFBid(String fbid) {
		User u = ofy.query(User.class).filter("fbID", fbid).get();
		if(u == null){
			return null;
		}
		else return u;//TODO: iterate
	}



	public void registerScore(RTentry entry) {
		ofy.put(entry);

		dirtybit.setDirty(1);//set to dirty
		ofy.put(dirtybit);//put in DB



		Query<User> q = (ofy.query(User.class).filter("bestScore <", entry.getScore())).filter("valid", Boolean.TRUE);

		String msg = "Message from donut-rush:\n" +
				"Your score in donut-rush has been beaten by "+ entry.getName()+"!\n" +
				"PLAY DONUT-RUSH NOW TO SAVE YOUR LOST RESPECT!\n";

		for (User u: q) {
			if (!entry.getName().equals(u.getName())){
				if (!u.isFacebookUser()){
					//send mail to him
					Mailman.sendTheMail("zzzoshri@gmail.com", u.getEmail(), u.getName(),
							"donut-rush: your score has been beaten!",
							msg+"donutrush.appspot.com");
				}
				else {
					FBMailman.postToWall(u.getFbID(), msg);
				}
			}
		}

	}

	public boolean registerUser(User u) {
		if(getUserByEmail(u.getEmail())!=null || getUserByName(u.getName()) != null){
			return false;
		}
		else{
			ofy.put(u);
			return true;
		}
	}

	public void updateUserScore(User u) {

		User oldUserObj = getUserByName(u.getName());

		if(oldUserObj.getBestScore() < u.getBestScore()){
			oldUserObj.setBestScore(u.getBestScore());
			ofy.put(oldUserObj);//this should run over the user object in th DB, because it has same ID generated by google appengine
		}

	}



	public boolean verifyUser(String user, String email, String pswd) {


		User u = ofy.query(User.class).filter("email", email).get();
		if (u==null){
			return false;
		}
		if(u.getPassword().equals(pswd) && u.getName().equals(user)){
			u.setValid(true);
			ofy.put(u);
		}

		return true;
	}


	//singleton implementation
	protected UserServiceDBimpl() {
		// Exists only to defeat instantiation.
	}
	public static UserServiceDBimpl getInstance() {
		if(instance == null) {
			instance = new UserServiceDBimpl();
			instance.init();
		}
		return instance;
	}



}
